package com.leetcode.array;

/**
 * @author: ZhouBert
 * @date: 2019/10/17
 * @description: 238. 除自身以外数组的乘积
 * B
 * <p>
 * 给定长度为 n 的整数数组 nums，其中 n > 1，返回输出数组 output ，其中 output[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积。
 * <p>
 * 示例:
 * 输入: [1,2,3,4]
 * 输出: [24,12,8,6]
 * 说明: 请不要使用除法，且在 O(n) 时间复杂度内完成此题。
 * <p>
 * 进阶：
 * 你可以在常数空间复杂度内完成这个题目吗？（ 出于对空间复杂度分析的目的，输出数组不被视为额外空间。）
 * <p>
 * 来源：力扣（LeetCode）
 * 链接：https://leetcode-cn.com/problems/product-of-array-except-self
 * 著作权归领扣网络所有。商业转载请联系官方授权，非商业转载请注明出处。
 */
public class ProductExceptSelf238B {

	/**
	 * 我的思路：
	 * todo:1.用除法算出总数。但是这个有个问题！如果元素存在0，那么就会求不出来！（相较+-*而言，除法运算消耗时间长，效率低，在一些对运行时间有要求的程序中尽量少用，可能的话可以使用位移运算代替）
	 * 暂且相信不用除法运算
	 * todo:2.看了答案的思路：遍历两遍，第一遍储存索引下该数左边的乘积；第二遍储存索引下该数右边的乘积。看来还是这个算法比较完美！
	 * todo:启发：算法的思路还是需要多用纸画一画
	 * @param nums
	 * @return
	 */
	public int[] productExceptSelf(int[] nums) {
		///1.结果数组（虽然有O(n)空间复杂度，但是不算额外空间）
		int[] res = new int[nums.length];
		int k = 1;
		///2.第一遍将左边进行乘积
		for (int i = 0; i < nums.length; i++) {
			res[i] = k;
			k *= nums[i];
		}
		///3.第二遍将左边进行乘积
		k=1;
		for (int i = nums.length-1; i >-1; i--) {
			res[i]*=k;
			k*=nums[i];
		}

		return res;

	}

	/**
	 * 这个有缺陷，先不用管了！
	 * @param nums
	 * @return
	 */
	public int[] productExceptSelfByDivision(int[] nums) {
		int sum = 1;
		int[] res = new int[nums.length];
		for (int i = 0; i < nums.length; i++) {
			sum *= nums[i];
		}
		for (int i = 0; i < nums.length; i++) {
			res[i] = sum / nums[i];
		}
		return res;
	}
}
